// SPDX-License-Identifier: GPL-2.0+
/*
 * Copyright (C) 2023-2024, Phytium Technology Co., Ltd.
 * lixinde			<lixinde@phytium.com.cn>
 * weichangzheng	<weichangzheng@phytium.com.cn>
 * This file describes the overall initialization function.
 */

#include <common.h>
#include <stdio.h>
#include <command.h>
#include <init.h>
#include <asm/armv8/mmu.h>
#include <asm/io.h>
#include <linux/arm-smccc.h>
#include <scsi.h>
#include <nvme.h>
#include <asm/u-boot.h>
#include <e_uart.h>
#include "cpu.h"
#include "board_init/board.h"
#include "power_manage/power_manage.h"

DECLARE_GLOBAL_DATA_PTR;

int mach_cpu_init(void)
{
	int ret;

	bmc_heart_beat();
	pwr_bmc_gpio_core_reset_enable();
	gpio_reset_device(GPIO_RESET_PCIE, 0);
	check_reset();

	/* reconfig qspi and iacc to solve the problem of slow startup speed after reset */
	if (gd->reset_flag == 0x03) {
		/* config d_buffer field */
		ret = readl(QSPI_ADDR_READ_CFG_REG);
		ret |= (1 << 3);
		writel(ret, QSPI_ADDR_READ_CFG_REG);
	}
	/* config iacc cache mode field */
	writel(0x0101, IACC_REG_BASE + REG_CACHE_MODE);

	bmc_clear_jpeg_int();

	return 0;
}

int board_early_init_f(void)
{
#ifdef PHYTIUM_PINCTRL_TOOLS
	pe2201_pin_ctrl();
#endif

	if (gd->reset_flag != 0x03) {
		mio_func_sel();
		gpio_reset_device(GPIO_RESET_PCIE, 1);

#ifdef PE2201_BMC
		bmc_smmu_setup();
#endif

		pcie_init();
		pe2201_phy_init();
	}

	usb_init_setup();
	vhub_init_setup();

	return 0;
}

int board_early_init_r(void)
{
	return 0;
}

int dram_init(void)
{
	uint32_t s3_flag;

	gd->mem_clk = 0;
	gd->ram_size = PHYS_SDRAM_1_SIZE;

	if (gd->reset_flag != 0x03) {
		s3_flag = 0;
		//get_s3_flag();
		//printf("s3_flag = %d\n", s3_flag);
		//pwr_s3_clean();
		printf("Phytium ddr init \n");
		pe2201_ddr_init(s3_flag);
	}

	sec_init(s3_flag);
	printf("PBF relocate done\n");

	return 0;
}

int dram_init_banksize(void)
{
	gd->bd->bi_dram[0].start = PHYS_SDRAM_1;
	gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE;

	return 0;
}

int board_init(void)
{
	if (gd->reset_flag != 0x03) {
		//gsd_sata_setup();
		//psu_sata_setup();
		onewire_init_setup();

#ifdef PHYTIUM_ETH_TRAIN
		phytium_eth_training();
#endif

	}

	register_pfdi();

	return 0;
}

void reset_cpu(ulong addr)
{
	struct arm_smccc_res res;

	debug("run in reset cpu\n");
	arm_smccc_smc(0x84000009, 0, 0, 0, 0, 0, 0, 0, &res);
	if (res.a0 != 0)
		panic("reset cpu error, %lx\n", res.a0);
}

/*
 * Initialize the page table to ensure correct and secure memory access
 */
static struct mm_region pe2201_mem_map[] = {
	{
		.virt = 0x0UL,
		.phys = 0x0UL,
		.size = 0x80000000UL,
		/* access to the page table */
		.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
				PTE_BLOCK_NON_SHARE | PTE_BLOCK_PXN | PTE_BLOCK_UXN
	},
	{
		.virt = (u64)PHYS_SDRAM_1,
		.phys = (u64)PHYS_SDRAM_1,
		.size = (u64)PHYS_SDRAM_1_SIZE,
		.attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) | PTE_BLOCK_NS | PTE_BLOCK_INNER_SHARE
	},
#ifdef PHYS_SDRAM_2
	{
		.virt = (u64)PHYS_SDRAM_2,
		.phys = (u64)PHYS_SDRAM_2,
		.size = (u64)PHYS_SDRAM_2_SIZE，
		.attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) | PTE_BLOCK_NS | PTE_BLOCK_INNER_SHARE
	},
#endif
	{
		0,
	}
};

struct mm_region *mem_map = pe2201_mem_map;

int last_stage_init(void)
{
#ifndef PE2201_BMC
	int ret;

	pci_init();
	scsi_scan(true);
	ret = nvme_scan_namespace();
	if (ret != 0)
		printf("nvme scan failed\n");
#else
	if (gd->reset_flag != 0x03) {
		scmi_bmc_jpeg_reset_delay();
#endif

#ifdef PHYTIUM_SAVE_TRAIN_DATA
		save_train_data();
#endif
		writel(0x0, LSD_NAND_MMCSD_HDDR);
	}
	bmc_init();

	return 0;
}
